/*
 * @文件描述:
 * @版本:
 * @作者:周晨阳
 * @Date:2021-08-24 19:35:02
 */

#include "fontupd.h"
#include "./src/ff.h"
#include "mySDIO.h"
#include "myFlash.h"
#include "string.h"
#include "rtthread.h"

//字库区域占用的总扇区数大小(3个字库+unigbk表+字库信息=3238700字节,约占791个W25QXX扇区)
#define FONTSECSIZE 791
//字库存放起始地址
#define FONTINFOADDR 1024 * 1024 * 12 //Explorer STM32F4是从12M地址以后开始存放字库                           \
									  //前面12M被fatfs占用了.                                                       \
									  //12M以后紧跟3个字库+UNIGBK.BIN,总大小3.09M,被字库占用了,不能动! \
									  //15.10M以后,用户可以自由使用.建议用最后的100K字节比较好.

//用来保存字库基本信息，地址，大小等
_font_info ftinfo;

//字库存放在磁盘中的路径
u8 *const GBK24_PATH = "/SYSTEM/FONT/GBK24.FON";   //GBK24的存放位置
u8 *const GBK16_PATH = "/SYSTEM/FONT/GBK16.FON";   //GBK16的存放位置
u8 *const GBK12_PATH = "/SYSTEM/FONT/GBK12.FON";   //GBK12的存放位置
u8 *const UNIGBK_PATH = "/SYSTEM/FONT/UNIGBK.BIN"; //UNIGBK.BIN的存放位置
u8 *const LVGL_FONT_PATH = "/font/myFont.bin";
//显示当前字体更新进度
//x,y:坐标
//size:字体大小
//fsize:整个文件大小
//pos:当前文件指针位置
u32 fupd_prog(u16 x, u16 y, u8 size, u32 fsize, u32 pos)
{
	float prog;
	u8 t = 0XFF;
	prog = (float)pos / fsize;
	prog *= 100;
	if (t != prog)
	{
		t = prog;
		if (t > 100)
			t = 100;
		printf("progress:%d %\n", t);
	}
	return 0;
}
//更新某一个
//x,y:坐标
//size:字体大小
//fxpath:路径
//fx:更新的内容 0,ungbk;1,gbk12;2,gbk16;3,gbk24;
//返回值:0,成功;其他,失败.
u8 updata_fontx(u16 x, u16 y, u8 size, u8 *fxpath, u8 fx)
{
	u32 flashaddr = 0;
	FIL *fftemp;
	u8 *tempbuf;
	u8 res;
	u16 bread;
	u32 offx = 0;
	u8 rval = 0;
	fftemp = (FIL *)rt_malloc(sizeof(FIL)); //分配内存
	if (fftemp == NULL)
		rval = 1;
	tempbuf = rt_malloc(4096); //分配4096个字节空间
	if (tempbuf == NULL)
		rval = 1;
	res = f_open(fftemp, (const TCHAR *)fxpath, FA_READ);
	if (res)
		rval = 2; //打开文件失败
	if (rval == 0)
	{
		switch (fx)
		{
		case 0:												 //更新UNIGBK.BIN
			ftinfo.ugbkaddr = FONTINFOADDR + sizeof(ftinfo); //信息头之后，紧跟UNIGBK转换码表
			ftinfo.ugbksize = fftemp->fsize;				 //UNIGBK大小
			flashaddr = ftinfo.ugbkaddr;
			break;
		case 1:
			ftinfo.f12addr = ftinfo.ugbkaddr + ftinfo.ugbksize; //UNIGBK之后，紧跟GBK12字库
			ftinfo.gbk12size = fftemp->fsize;					//GBK12字库大小
			flashaddr = ftinfo.f12addr;							//GBK12的起始地址
			break;
		case 2:
			ftinfo.f16addr = ftinfo.f12addr + ftinfo.gbk12size; //GBK12之后，紧跟GBK16字库
			ftinfo.gbk16size = fftemp->fsize;					//GBK16字库大小
			flashaddr = ftinfo.f16addr;							//GBK16的起始地址
			break;
		case 3:
			ftinfo.f24addr = ftinfo.f16addr + ftinfo.gbk16size; //GBK16之后，紧跟GBK24字库
			ftinfo.gkb24size = fftemp->fsize;					//GBK24字库大小
			flashaddr = ftinfo.f24addr;							//GBK24的起始地址
			break;
		case 4:
			ftinfo.lvglFontAddr = ftinfo.f24addr + ftinfo.gkb24size; //GBK16之后，紧跟GBK24字库
			ftinfo.lvglFontSize = fftemp->fsize;					 //GBK24字库大小
			flashaddr = ftinfo.lvglFontAddr;						 //GBK24的起始地址

			break;
		}

		while (res == FR_OK) //死循环执行
		{
			res = f_read(fftemp, tempbuf, 4096, (UINT *)&bread); //读取数据
			if (res != FR_OK)
				break;									   //执行错误
			W25QXX_Write(tempbuf, offx + flashaddr, 4096); //从0开始写入4096个数据
			offx += bread;
			fupd_prog(x, y, size, fftemp->fsize, offx); //进度显示
			if (bread != 4096)
				break; //读完了.
		}
		W25QXX_Write((u8 *)&ftinfo, FONTINFOADDR, sizeof(ftinfo)); //保存字库信息

		f_close(fftemp);
	}
	rt_free(fftemp);  //释放内存
	rt_free(tempbuf); //释放内存
	return res;
}
//更新字体文件,UNIGBK,GBK12,GBK16,GBK24一起更新
//x,y:提示信息的显示地址
//size:字体大小
//src:字库来源磁盘."0:",SD卡;"1:",FLASH盘,"2:",U盘.
//提示信息字体大小
//返回值:0,更新成功;
//		 其他,错误代码.
u8 update_font(u16 x, u16 y, u8 size, u8 *src)
{
	u8 *pname;
	u32 *buf;
	u8 res = 0;
	u16 i, j;
	FIL *fftemp;
	u8 rval = 0;
	res = 0XFF;
	ftinfo.fontok = 0XFF;
	pname = rt_malloc(100);					//申请100字节内存
	buf = rt_malloc(4096);					//申请4K字节内存
	fftemp = (FIL *)rt_malloc(sizeof(FIL)); //分配内存
	if (buf == NULL || pname == NULL || fftemp == NULL)
	{
		rt_free(fftemp);
		rt_free(pname);
		rt_free(buf);
		return 5; //内存申请失败
	}
	//先查找文件是否正常
	strcpy((char *)pname, (char *)src); //copy src内容到pname
	strcat((char *)pname, (char *)UNIGBK_PATH);
	res = f_open(fftemp, (const TCHAR *)pname, FA_READ);
	if (res)
		rval |= 1 << 4;					//打开文件失败
	strcpy((char *)pname, (char *)src); //copy src内容到pname
	strcat((char *)pname, (char *)GBK12_PATH);
	res = f_open(fftemp, (const TCHAR *)pname, FA_READ);
	if (res)
		rval |= 1 << 5;					//打开文件失败
	strcpy((char *)pname, (char *)src); //copy src内容到pname
	strcat((char *)pname, (char *)GBK16_PATH);
	res = f_open(fftemp, (const TCHAR *)pname, FA_READ);
	if (res)
		rval |= 1 << 6;					//打开文件失败
	strcpy((char *)pname, (char *)src); //copy src内容到pname
	strcat((char *)pname, (char *)GBK24_PATH);
	res = f_open(fftemp, (const TCHAR *)pname, FA_READ);
	if (res)
		rval |= 1 << 7; //打开文件失败
	rt_free(fftemp);	//释放内存

	if (rval == 0) //字库文件都存在.
	{
		//////LCD_ShowString(x,y,240,320,size,"Erasing sectors... ");//提示正在擦除扇区
		for (i = 0; i < FONTSECSIZE; i++) //先擦除字库区域,提高写入速度
		{
			fupd_prog(x + 20 * size / 2, y, size, FONTSECSIZE, i);			  //进度显示
			W25QXX_Read((u8 *)buf, ((FONTINFOADDR / 4096) + i) * 4096, 4096); //读出整个扇区的内容
			for (j = 0; j < 1024; j++)										  //校验数据
			{
				if (buf[j] != 0XFFFFFFFF)
					break; //需要擦除
			}
			if (j != 1024)
				W25QXX_Erase_Sector((FONTINFOADDR / 4096) + i); //需要擦除的扇区
		}
		rt_free(buf);
		////LCD_ShowString(x,y,240,320,size,"Updating UNIGBK.BIN");
		strcpy((char *)pname, (char *)src); //copy src内容到pname
		strcat((char *)pname, (char *)UNIGBK_PATH);
		res = updata_fontx(x + 20 * size / 2, y, size, pname, 0); //更新UNIGBK.BIN
		if (res)
		{
			rt_free(pname);
			return 1;
		}
		////LCD_ShowString(x,y,240,320,size,"Updating GBK12.BIN  ");
		strcpy((char *)pname, (char *)src); //copy src内容到pname
		strcat((char *)pname, (char *)GBK12_PATH);
		res = updata_fontx(x + 20 * size / 2, y, size, pname, 1); //更新GBK12.FON
		if (res)
		{
			rt_free(pname);
			return 2;
		}
		////LCD_ShowString(x,y,240,320,size,"Updating GBK16.BIN  ");
		strcpy((char *)pname, (char *)src); //copy src内容到pname
		strcat((char *)pname, (char *)GBK16_PATH);
		res = updata_fontx(x + 20 * size / 2, y, size, pname, 2); //更新GBK16.FON
		if (res)
		{
			rt_free(pname);
			return 3;
		}
		////LCD_ShowString(x,y,240,320,size,"Updating GBK24.BIN  ");
		strcpy((char *)pname, (char *)src); //copy src内容到pname
		strcat((char *)pname, (char *)GBK24_PATH);
		res = updata_fontx(x + 20 * size / 2, y, size, pname, 3); //更新GBK24.FON
		if (res)
		{
			rt_free(pname);
			return 4;
		}

		//全部更新好了
		ftinfo.fontok = 0XAA;
		W25QXX_Write((u8 *)&ftinfo, FONTINFOADDR, sizeof(ftinfo)); //保存字库信息
	}
	rt_free(pname); //释放内存
	rt_free(buf);
	return rval; //无错误.
}
//初始化字体
//返回值:0,字库完好.
//		 其他,字库丢失
u8 font_init(void)
{
	u8 t = 0;
	W25QXX_Init();
	while (t < 10) //连续读取10次,都是错误,说明确实是有问题,得更新字库了
	{
		t++;
		W25QXX_Read((u8 *)&ftinfo, FONTINFOADDR, sizeof(ftinfo)); //读出ftinfo结构体数据
		if (ftinfo.fontok == 0XAA)
			break;
		delay_ms(20);
	}
	if (ftinfo.fontok != 0XAA)
		return 1;
	printf("UNIGBK.BIN Addr:0x%x,size:%lu kb\n", ftinfo.ugbkaddr, ftinfo.ugbksize / 1024);
	printf("GBK12.BIN Addr:0x%x,size:%lu kb\n", ftinfo.f12addr, ftinfo.gbk12size / 1024);
	printf("GBK16.BIN Addr:0x%x,size:%lu kb\n", ftinfo.f16addr, ftinfo.gbk16size / 1024);
	printf("GBK24.BIN Addr:0x%x,size:%lu kb\n", ftinfo.f24addr, ftinfo.gkb24size / 1024);
	printf("lvglFont Addr:0x%x,size:%lu kb\n", ftinfo.lvglFontAddr, ftinfo.lvglFontSize / 1024);
	return 0;
}
